#ifndef BMP_H
#define BMP_H

#include <string.h>
#include "bitmap.h"

namespace Library
{

/**
 * A concrete class for creating and modifying Windows BMPs.
 *
 * Bmp provides high-level methods for unrestricted access to the low-level
 * internal data structures, color table, and image data of Windows 3.0 BMP
 * files.  These methods do not provide data validation, only simplified data
 * access.  Therefore, it is up to the user to ensure all data meets Windows
 * 3.0 BMP file format specifications.
 *
 * <b>Warning:</b> Malformed BMPs, when saved to disk, will cause Microsoft
 * Explorer to behave undesirably.  You've been warned!
 */
class Bmp
{
	public:
		struct FileHeader;
		struct InfoHeader;
		struct ColorTable;
		struct MetaInfoHeader;

	public:
						Bmp();
						Bmp(Bmp & src);
						~Bmp();

		void			bitsPerPixel(uint16 bpp);
		uint16			bitsPerPixel();

		void			colorsImportant(uint32 colors);
		uint32			colorsImportant();

		void			colorsUsed(uint32 colors);
		uint32			colorsUsed();

		void			colorTable(ColorTable * aColorTable);
		ColorTable *	colorTable();

		enum Compression { rgb = 0, rle8 = 1, rle4 = 2, bitfields = 3 };
		void			compression(Compression type);
		uint32			compression();

		bool8			decodeImage();
		bool8			decodeImageUnpad();
		bool8			decodeImageRLE4();
		bool8			decodeImageRLE8();

		bool8			encodeImage();
		bool8			encodeImagePad();
		bool8			encodeImageRLE4();
		bool8			encodeImageRLE8();

		bool8			erectImage();

		void			fileHeader(FileHeader * aFileHeader);
		FileHeader *	fileHeader();

		void			fileMagic(uint16 magic);
		uint16			fileMagic();

		void			fileSize(uint32 size);
		uint32			fileSize();

		bool8			flipImage();

		void			height(int32 pixels);
		uint32			height();

		void			image(uint8 * anImage);
		void			image(uint8 * anImage, uint32 ofSize);
		uint8 *			image();

		void			imageOffset(uint32 offset);
		uint32			imageOffset();

		int32			imageOrientation();

		void			imageSize(uint32 size);
		uint32			imageSize();

		void			infoHeader(InfoHeader * aInfoHeader);
		InfoHeader *	infoHeader();

		bool8			invertImage();

		bool8			load(const String & filename);

		void			metaInfoHeader(MetaInfoHeader * aMetaInfoHeader);
		MetaInfoHeader *metaInfoHeader();

		uint32			paletteEntries();

		bool8			paletteIndexOf(uint8 red, uint8 green, uint8 blue,
							uint32 * index);

		uint32			paletteSize();

		void			pixelsPerMeterX(uint32 ppmx);
		uint32			pixelsPerMeterX();

		void			pixelsPerMeterY(uint32 ppmx);
		uint32			pixelsPerMeterY();

		void			planes(uint16 count);
		uint16			planes();

		void			reset();

		bool8			save(const String & filename);

		void			width(uint32 pixels);
		uint32			width();

        // kharmon.  01-09-07.  Adding ability to decompile .rsc files.
        void loadBitmap(CBitmapBuffer *pBmpBuf);
        bool8 loadAlphaBitmap(CBitmapBuffer *pBmpBuf);

	protected:
		FileHeader *	mFileHeader;
		InfoHeader *	mInfoHeader;		// == &mMetaInfoHeader.infoHeader
		ColorTable *	mColorTable;		// == &mMetaInfoHeader.colorTable
		MetaInfoHeader *mMetaInfoHeader;
		uint8 *			mImage;

	// prohibited
	private:
		Bmp & operator=(Bmp &);
};

//----------------------------------------------------------------------------
// Structs, public
//
#pragma pack(push, 1)
/**
 * A cross-platform structure compatible with BITMAPFILEHEADER.
 */
struct Bmp::FileHeader
{
	// "BM" in little-endian format.
	#define BMP_MAGIC	0x4d42
	uint16	magic;
	uint32	fileSize;
	uint32	reserved;
	uint32	imageOffset;
};

/**
 * A cross-platform structure compatible with BITMAPINFOHEADER.
 */
struct Bmp::InfoHeader
{
	uint32	headerSize;
	uint32	width;
	int32	height;
	uint16	planes;
	uint16	bitsPerPixel;
	uint32	compression;
	uint32	imageSize;
	uint32	xPixelsPerMeter;
	uint32	yPixelsPerMeter;
	uint32	colorsUsed;
	uint32	colorsImportant;
};

/**
 * A cross-platform structure which defines a BMP color table.
 */
struct Bmp::ColorTable
{
	RGBQuad	palette[256];
};

/**
 * A cross-platform structure compatible with BITMAPINFO.
 */
struct Bmp::MetaInfoHeader
{
	InfoHeader	infoHeader;
	ColorTable	colorTable;
};
#pragma pack(pop)


//----------------------------------------------------------------------------
// Inline, public
//

/**
 * @param bpp		The number of bits per pixel.
 *
 * This methods sets the bits per pixel of the image.
 *
 * <b>Specification:</b>  While it's possible to set this to any value, the
 * Windows specification defines values 1, 2, 4, 8, 16, 24, and 32 as the
 * only valid settings.
 */
inline void
Bmp::bitsPerPixel(uint16 bpp)
{
	mInfoHeader->bitsPerPixel = bpp;
}

/**
 * This methods gets the bits per pixel of the image.
 */
inline uint16
Bmp::bitsPerPixel()
{
	return mInfoHeader->bitsPerPixel;
}

/**
 * @param colors	The number important color indexes.
 *
 * This methods sets the number of color indexes that are considered important
 * for displaying.  If this value is 0, then all colors are important.
 */
inline void
Bmp::colorsImportant(uint32 colors)
{
	mInfoHeader->colorsImportant = colors;
}

/**
 * This methods gets the number of color indexes that are considered important
 * for displaying.  If this value is 0, then all colors are important.
 */
inline uint32
Bmp::colorsImportant()
{
	return mInfoHeader->colorsImportant;
}

/**
 * @param colors	The number color indexes in the color table used by the
 *					bitmap.
 *
 * This methods sets the number of color indexes in the color table actually
 * used by the bitmap.  If this value is 0, the bitmap uses the maximum number
 * of colors corresponding to the value obtained from bitsPerPixel().
 */
inline void
Bmp::colorsUsed(uint32 colors)
{
	mInfoHeader->colorsUsed = colors;
}

/**
 * This methods gets the number of color indexes in the color table actually
 * used by the bitmap.  If this value is 0, the bitmap uses the maximum number
 * of colors corresponding to the value obtained from bitsPerPixel().
 */
inline uint32
Bmp::colorsUsed()
{
	return mInfoHeader->colorsUsed;
}

/**
 * @param aColorTable	A pointer to a ColorTable to be duplicated.
 *
 * This methods sets the color table of the bitmap by copying the RGBQuad
 * values specified in @p aColorTable.
 */
inline void
Bmp::colorTable(ColorTable * aColorTable)
{
	mMetaInfoHeader->colorTable = *aColorTable;
}

/**
 * This methods gets a pointer to the current color table.
 */
inline Bmp::ColorTable *
Bmp::colorTable()
{
	return &mMetaInfoHeader->colorTable;
}

/**
 * @param type		Type of compression.
 *
 * This methods sets the type of compression for a bitmap.
 *
 * Valid values:
 *		@arg @p rgb			specifies that the bitmap is not compressed.
 *		@arg @p rle8		specifies a run-length encoded format for bitmaps
 *							with 8 bits per pixel.
 *		@arg @p rle4		specifies a run-length encoded format for bitmaps
 *							with 4 bits per pixel.
 *		@arg @p bitfields	specifies that the bitmap is not compressed and
 *							that the first three (3) entries of the color
 *							table are RGB color masks for bitmaps with 16
 *							and 32 bits per pixel.
 */
inline void
Bmp::compression(Compression type)
{
	mInfoHeader->compression = type;
}

inline uint32
Bmp::compression()
{
	return mInfoHeader->compression;
}

inline void
Bmp::fileHeader(FileHeader * aFileHeader)
{
	*mFileHeader = *aFileHeader;
}

inline Bmp::FileHeader *
Bmp::fileHeader()
{
	return mFileHeader;
}

inline void
Bmp::fileMagic(uint16 magic)
{
	mFileHeader->magic = magic;
}

inline uint16
Bmp::fileMagic()
{
	return mFileHeader->magic;
}

inline void
Bmp::fileSize(uint32 size)
{
	mFileHeader->fileSize = size;
}

inline uint32
Bmp::fileSize()
{
	return mFileHeader->fileSize;
}

inline void
Bmp::height(int32 pixels)
{
	mInfoHeader->height = pixels;
}

/**
 * NOTE: If you need a signed height, use imageOrientation()!
 */
inline uint32
Bmp::height()
{
	return ABS(mInfoHeader->height);
}

inline void
Bmp::image(uint8 * anImage)
{
	delete [] mImage;

	mImage = anImage;
}

inline void
Bmp::image(uint8 * anImage, uint32 ofSize)
{
	delete [] mImage;
	mImage = new uint8[ ofSize ];
	if (mImage)
	{
		memcpy(mImage, anImage, ofSize);
		imageSize(ofSize);
	}
	else
		imageSize(0);
}

inline uint8 *
Bmp::image()
{
	return mImage;
}

inline void
Bmp::imageOffset(uint32 offset)
{
	mFileHeader->imageOffset = offset;
}

inline uint32
Bmp::imageOffset()
{
	return mFileHeader->imageOffset;
}

inline int32
Bmp::imageOrientation()
{
	return mInfoHeader->height;
}

inline void
Bmp::imageSize(uint32 size)
{
	mInfoHeader->imageSize = size;
}

inline uint32
Bmp::imageSize()
{
	return mInfoHeader->imageSize;
}

inline void
Bmp::infoHeader(InfoHeader * aInfoHeader)
{
	*mInfoHeader = *aInfoHeader;
}

inline Bmp::InfoHeader *
Bmp::infoHeader()
{
	return mInfoHeader;
}

inline void
Bmp::metaInfoHeader(MetaInfoHeader * aMetaInfoHeader)
{
	*mMetaInfoHeader = *aMetaInfoHeader;
}

inline Bmp::MetaInfoHeader *
Bmp::metaInfoHeader()
{
	return mMetaInfoHeader;
}

inline uint32
Bmp::paletteSize()
{
	return paletteEntries() * sizeof RGBQuad;
}

inline void
Bmp::pixelsPerMeterX(uint32 ppmx)
{
	mInfoHeader->xPixelsPerMeter = ppmx;
}

inline uint32
Bmp::pixelsPerMeterX()
{
	return mInfoHeader->xPixelsPerMeter;
}

inline void
Bmp::pixelsPerMeterY(uint32 ppmy)
{
	mInfoHeader->xPixelsPerMeter = ppmy;
}

inline uint32
Bmp::pixelsPerMeterY()
{
	return mInfoHeader->yPixelsPerMeter;
}

inline void
Bmp::planes(uint16 count)
{
	mInfoHeader->planes = count;
}

inline uint16
Bmp::planes()
{
	return mInfoHeader->planes;
}

inline void
Bmp::width(uint32 pixels)
{
	mInfoHeader->width = pixels;
}

inline uint32
Bmp::width()
{
	return mInfoHeader->width;
}

}; // namespace Library

#endif
